package jee.boot.module.iexp.task.impl;

import com.github.pagehelper.util.StringUtil;
import jee.boot.common.basic.DataEntity;
import jee.boot.common.basic.ServiceException;
import jee.boot.common.properties.ProjectConfig;
import jee.boot.common.remote.RemoteEndpoint;
import jee.boot.common.standard.AccountHandler;
import jee.boot.common.standard.AuthorityHandler;
import jee.boot.common.standard.DocumentStorageClient;
import jee.boot.common.utils.JsonMapper;
import jee.boot.common.utils.SpringContextHolder;
import jee.boot.common.utils.StringUtils;
import jee.boot.common.utils.excel.excel.ErrorMessage;
import jee.boot.entity.task.IexpTaskConfig;
import jee.boot.entity.task.IexpTask;
import jee.boot.module.iexp.excel.excel.ExcelImport;
import jee.boot.module.iexp.service.IexpTaskService;
import jee.boot.entity.task.ImportExecuteService;
import jee.boot.module.iexp.task.TaskListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.io.File;
import java.util.*;

/**
 * 导入任务运行线程
 */
public class ImpRunnable extends BasicTaskRunnable  implements Runnable  {
    private Logger logger = LoggerFactory.getLogger(TaskListener.class);
    public ImpRunnable(IexpTask task, IexpTaskService iexpTaskService, DocumentStorageClient fileService, AuthorityHandler authorityHandler, AccountHandler accountHandler, RemoteEndpoint remoteEndpoint, ProjectConfig projectConfig) {
        this.task = task;
        this.iexpTaskService = iexpTaskService;
        this.fileService = fileService;
        super.authorityHandler=authorityHandler;
        super.accountHandler=accountHandler;
        super.remoteEndpoint=remoteEndpoint;
        super.projectConfig=projectConfig;
    }

    private IexpTaskService iexpTaskService;
    private IexpTask task;
    private DocumentStorageClient fileService;


    @Override
    public void run() {
        logger.debug("后台导入任务[" + task.getName() + "(" + task.getId() + ")]开始执行");
//            if (task.getPriority() != 0) {
//                //线程优先级默认是5 设置区间1-10
////                Thread currentThread = Thread.currentThread();
////                currentThread.setPriority(task.getPriority());
//            }

        configThreadPermission(task);
        task.setStartDate(new Date());
        ImportExecuteService service = null;
        Set<String> errors = new HashSet<>();
        try {
            String delegatedClass = task.getDelegatedClass();
            if (StringUtils.isBlank(delegatedClass)) {
                throw new Exception("委托服务类[delegatedClass]不能为空");
            }

            // 全路径,需要使用反射
            if (StringUtils.contains(delegatedClass, ".")) {
                Class<?> classService = Class.forName(delegatedClass);
                Object classObject = classService.newInstance();
                if (!(classObject instanceof ImportExecuteService)) {
                    throw new Exception("委托服务类[delegatedClass]需要实现ImportExecuteService接口");
                }
                service = (ImportExecuteService) classObject;
            } else {
                Object classObject = SpringContextHolder.getBean(delegatedClass);
                if (!(classObject instanceof ImportExecuteService)) {
                    throw new Exception("委托服务类[delegatedClass]需要实现ImportExecuteService接口");
                }
                service = (ImportExecuteService) classObject;
            }
            //前置处理
            service.preProcess(task);
            // 获取配置类
            IexpTaskConfig config = service.taskConfig(task);

            // 判断是否为自定义EXCEL下载
            // 如果为自定义EXCEL下载，不进行后续操作
            String jsonParam = task.getJsonParam();
            if (!(StringUtil.isEmpty(jsonParam))) {
                Map map = JsonMapper.fromJsonString(jsonParam, Map.class);
                String extraFlag = map.get("extraFlag") == null ? "N" : (String) map.get("extraFlag");
                if ("Y".equals(extraFlag)) {
                    // 任务完成后置处理
                    service.postProcess(task);
                    return;
                }
            }
            // 获取文件
            // 更换为文件服务控制,可实现不同方式的文件存储
            File file = fileService.downloadToFile(task.getAttachment().getId());
            if (!file.exists()) {
                throw new Exception("文件[" + task.getFileName() + "]不存在");
            }
            Map<String, Object> checkMap = service.preFileCheck(file, task, task.getJsonParam());
            if (checkMap.get("ifEndTask").equals(true)) {
                task.setMessage(checkMap.get("message") != null ? checkMap.get("message").toString() : null);
                task.setIexpStatus("iexp_status_error");
                task.setEndDate(new Date());
                // 任务完成后置处理
                service.postProcess(task);
                iexpTaskService.update(task);
                if (checkMap.get("message") != null) {
                    if (checkMap.get("message") instanceof HashSet) {
                        errors.addAll((Set) checkMap.get("message"));
                    } else if (checkMap.get("message") instanceof ArrayList) {
                        errors.addAll(new HashSet<>((List) checkMap.get("message")));
                    } else {
                        if (!StringUtils.isEmpty(checkMap.get("message").toString())) {
                            errors.add(checkMap.get("message").toString());
                        }
                    }
                }
                service.errorHandler(errors, task);
                return;
            } else {
                if (checkMap.get("message") != null) {
                    if (checkMap.get("message") instanceof HashSet) {
                        errors.addAll((Set) checkMap.get("message"));
                    } else if (checkMap.get("message") instanceof ArrayList) {
                        errors.addAll(new HashSet<>((List) checkMap.get("message")));
                    } else {
                        if (!StringUtils.isEmpty(checkMap.get("message").toString())) {
                            errors.add(checkMap.get("message").toString());
                        }
                    }
                }
            }
            // 这里支持动态参数传入
            String json = task.getJsonParam();
            int headerNum = 2;
            Object sheetIndexOrName = new Object();
            if (StringUtils.isNotBlank(json)) {
                Map<String, Object> param = JsonMapper.fromJsonString(json, Map.class);
                param.putAll(service.setSheetAndEntitys(file, task, json));
                if (param.containsKey("headerNum")) {
                    headerNum = (int) param.get("headerNum");
                }
                if (param.containsKey("sheetIndexOrName")) {
                    sheetIndexOrName = param.get("sheetIndexOrName");
                }
                if (param.containsKey("sheetAndEntitys")) {
                    sheetIndexOrName = (List<Map<String, Object>>) param.get("sheetAndEntitys");
                }
            } else {
                sheetIndexOrName = (int) 0;
            }
            Map<String, Object> storeDataMap = new HashMap<>();
            ExcelImport ei = new ExcelImport(file, headerNum);
            Map<String, Object> errorMessageMap = new HashMap<>();
            if (sheetIndexOrName instanceof ArrayList) {
                for (Map<String, Object> sheet : (List<Map<String, Object>>) sheetIndexOrName) {
                    Class impClass;
                    if (sheet.get("importEntityClass") instanceof String) {
                        impClass = Class.forName((String) sheet.get("importEntityClass"));
                    } else {
                        impClass = (Class) sheet.get("importEntityClass");
                    }
                    if (sheet.containsKey("headerNum")) {
                        headerNum = (int) sheet.get("headerNum");
                    }
                    ei.setSheet(sheet.get("sheetIndexOrName"), headerNum);
                    // 如果是map形式的返回结果,需要设置区域
                    if (impClass.equals(Map.class)) {
                        String startColumn = sheet.containsKey("startColumn") ? (String) sheet.get("startColumn") : "A";
                        String endColumn = sheet.containsKey("endColumn") ? (String) sheet.get("endColumn") : "Z";
                        int startRow = sheet.containsKey("startRow") ? (int) sheet.get("startRow") : -1;
                        int endRow = sheet.containsKey("endRow") ? (int) sheet.get("endRow") : -1;
                        ei.configArea(startColumn, endColumn, startRow, endRow);
                    }
                    List<Object> list = ei.getDataList(impClass);
                    List<ErrorMessage> errorMessageLst = new ArrayList<ErrorMessage>();

                    for (ErrorMessage temp : ei.getErrorMessageList()) {
                        ErrorMessage tempCopy = new ErrorMessage();
                        BeanUtils.copyProperties(temp, tempCopy);
                        errorMessageLst.add(tempCopy);
                    }
                    errorMessageMap.put(sheet.get("sheetIndexOrName").toString(), errorMessageLst);
                    if (list != null && !list.isEmpty()) {
                        list.forEach(data -> {
                            if (data instanceof DataEntity) {
                                ((DataEntity) data).setCreateBy(accountHandler.getPrincipal());
                                ((DataEntity) data).setUpdateBy(accountHandler.getPrincipal());
                            }
                        });
                    }
                    storeDataMap.put(sheet.get("sheetIndexOrName").toString(), list);
                }
            } else {
                Class<? extends DataEntity> impClass = config.getImportEntityClass();
                //ei = new ExcelImport(file, headerNum, sheetIndexOrName);
                ei.setSheet(sheetIndexOrName, headerNum);
                List<? extends DataEntity> list = ei.getDataList(impClass);
                if (list != null && !list.isEmpty()) {
                    list.forEach(data -> {
                        if (data instanceof DataEntity) {
                            ((DataEntity) data).setCreateBy(accountHandler.getPrincipal());
                            ((DataEntity) data).setUpdateBy(accountHandler.getPrincipal());
                        }
                    });
                }
                errorMessageMap.put(sheetIndexOrName.toString(), ei.getErrorMessageList());
                storeDataMap.put(sheetIndexOrName.toString(), list);
            }
            Set<String> analysisErrors = this.analysisErrorMessage(errorMessageMap);
            //errors.addAll(analysisErrors);
            Map<String, Object> checkDataMap = service.preDataCheck(storeDataMap, analysisErrors, task);
            if (checkDataMap.get("ifEndTask").equals(true)) {
                if (checkDataMap.get("message") != null) {
                    if (checkDataMap.get("message") instanceof HashSet) {
                        errors.addAll((Set) checkDataMap.get("message"));
                    } else if (checkDataMap.get("message") instanceof ArrayList) {
                        errors.addAll(new HashSet<>((List) checkDataMap.get("message")));
                    } else {
                        if (!StringUtils.isEmpty(checkDataMap.get("message").toString())) {
                            errors.add(checkDataMap.get("message").toString());
                        }
                    }
                }
                task.setMessage(!errors.isEmpty() ? StringUtils.join(errors.toArray(), "|") : null);
                task.setIexpStatus("iexp_status_error");
                task.setEndDate(new Date());
                // 任务完成后置处理
                service.postProcess(task);
                iexpTaskService.update(task);
                service.errorHandler(errors, task);
                return;
            } else {
                if (checkDataMap.get("message") != null) {
                    if (checkDataMap.get("message") instanceof HashSet) {
                        errors.addAll((Set) checkDataMap.get("message"));
                    } else if (checkDataMap.get("message") instanceof ArrayList) {
                        errors.addAll(new HashSet<>((List) checkDataMap.get("message")));
                    } else {
                        if (!StringUtils.isEmpty(checkDataMap.get("message").toString())) {
                            errors.add(checkDataMap.get("message").toString());
                        }
                    }
                }
            }
            task.setIexpStatus("iexp_status_success");
            task.setMessage(!errors.isEmpty() ? StringUtils.join(errors.toArray(), "|") : "success");
            //事务处理
            DataSourceTransactionManager dataSourceTransactionManager = SpringContextHolder.getBean(DataSourceTransactionManager.class);
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别，开启新事务
            TransactionStatus transaction = dataSourceTransactionManager.getTransaction(def); // 获得事务状态
            try {
                service.storeData(task, !(sheetIndexOrName instanceof ArrayList) ? storeDataMap.get(sheetIndexOrName.toString()) : storeDataMap);
                //提交事务
                dataSourceTransactionManager.commit(transaction);
            } catch (Exception e) {
                logger.warn("存储数据异常，回滚业务数据");
                //事务回滚
                dataSourceTransactionManager.rollback(transaction);
                throw e;
            } finally {
                if (ei != null) {
                    ei.close();
                }
            }
        }catch (ServiceException e) {
            logger.error(e.getMessage(), e);
            task.setMessage(getMessageCodeHelper().getMessage(e.getCode(),e.getData(),""));
            task.setIexpStatus("iexp_status_error");
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            task.setMessage(e.getMessage());
            task.setIexpStatus("iexp_status_error");
        }
        // 更新任务状态以及任务日志
        task.setEndDate(new Date());
        // 任务完成后置处理
        service.postProcess(task);
        iexpTaskService.update(task);
        service.errorHandler(errors, task);
    }

    private Set analysisErrorMessage(Map<String, Object> errorMessageMap) {
        Set<String> typeErrors = new HashSet<>();
        errorMessageMap.entrySet().forEach(errorMap -> {
            List<ErrorMessage> errorMessageList = (List<ErrorMessage>) errorMap.getValue();
            if (!errorMessageList.isEmpty()) {
                for (ErrorMessage errorMessage : errorMessageList) {
                    if (errorMessage.getType().equals(ErrorMessage.ErrorType.IllegalArgumentException)) {
                        StringBuilder errorBuilder = new StringBuilder();
                        errorBuilder.append("Sheet[");
                        errorBuilder.append(errorMap.getKey());
                        errorBuilder.append("]");
                        errorBuilder.append("第" + errorMessage.getX() + "行,第" + errorMessage.getY() + "列->" + errorMessage.getMessage());
                        typeErrors.add(errorBuilder.toString());
                    }
                }
            }
        });
        return typeErrors;
    }
}
